
#include "jncValidate.h"

void makeConstantVoid(CplInfo& x, RtmInfo& y) 
{
  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
  std::string tmp("p_void");
  tmp += std::string(CLASSDELM + tmp);
  CplInfo tx(computeId(tmp.c_str()));
  tx.setPriority(NORMAL);
  tx.setSymbolicName(tmp);
  tx.setType(P_JVOID);
  tmp = x.getSymbolicName();
  x = tx;
  boost::char_separator<char> sep(CLASSDELM);
  tokenizer tokens(tmp, sep);
  assert(tokens.begin() != tokens.end());
  std::vector<std::string> vs; // class fn and arg
  for(boost::tokenizer<boost::char_separator<char> >::iterator i = tokens.begin(); i != tokens.end(); i++)
    vs.push_back(*i);
  std::string val((--vs.end())->begin(), ((--vs.end())->begin() + (--vs.end())->length()));
  gReturnCode d((std::string*)new std::string(val));
  forceReturn(&y, d);
  y.setState(COMPLETE);
}

gReturnCode forceReturn(RtmInfo* r, gReturnCode& v) {
  r->ret = v;
  return r->ret;
}

void makeConstantExpr(CplInfo& x, RtmInfo& y) 
{
  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
  gReturnCode val(getVarValue(x.getSymbolicName()));
  if(val.empty())
    {
      std::string str(std::string("p_void") + CLASSDELM);
      str += str + x.getSymbolicName();
      x.setSymbolicName(str);
      makeConstantVoid(x, y);
    }
  else
    {
      forceReturn(&y, val);
      y.setState(COMPLETE);
    }
}

std::string getClassName(std::string s) {
  typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
  boost::char_separator<char> sep(CLASSDELM);
  tokenizer tokens(s, sep);
  if(tokens.begin() != tokens.end())
    return *tokens.begin();
}

bool isPtrVoid(std::string s) {
  bool b;
  if(!s.length())
    return false;
  if(!strncmp(getClassName(s).c_str(), "p_void", strlen("p_void")))
    b = true;
  else
    b = false;
  return b;
}


void resolve(CplInfo& ci, RtmInfo& ri) {
  
  if(isPtrVoid(ci.getSymbolicName()))
    makeConstantVoid(ci, ri);
  else
    makeConstantExpr(ci, ri); // resolve variable names
}

void finalBinding(CplInfo& cpl, RtmInfo& rtm) {
  if(cpl.getId() == UNSET)
    resolve(cpl, rtm);
  assert(cpl.getArgInfo().size() == rtm.getArg().size());
  for(int i = 0; i < cpl.getArgInfo().size();i++)
    if(cpl.getArgInfo()[i].getId() == UNSET)
      resolve(cpl.getArgInfo()[i], rtm.getArg()[i]);
    else
      finalBinding(cpl.getArgInfo()[i], rtm.getArg()[i]);
}

void execute(RtmInfo& r) {
  r.setReturn();
  gReturnCode tmp = r.getResult();
}

void eval(JncContext& c) {
  finalBinding(*(c.oci), *(c.ori));
  try {
    execute(*(c.ori));
  }
  catch(boost::bad_any_cast& e) {
    typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
    boost::char_separator<char> sep(CLASSDELM);
    tokenizer tokens(c.oci->getSymbolicName(), sep);
    assert(tokens.begin() != tokens.end());
    std::string tmp(std::string("In ") + *tokens.begin() + "(");
    for(boost::tokenizer<boost::char_separator<char> >::iterator i = ++tokens.begin(); i != tokens.end(); i++)
      tmp += *i + ",";
    std::string msg(std::string(tmp.begin(), --tmp.end()) + ")");
    msg += std::string(":\n") + ((RnException*)&e)->what();
    throw RnException(((RnException*)&e)->getCode(), msg.c_str(), e);
  }
}
